import core.ui.Window;

/**
 * Class used to highlight DOM elements.
 */
class xcms.plugins.editor.Selection {

    /**
     * Initializes the new selection.
     */
    this.Selection = function() {
        this.top = this.createEdge();
        this.right = this.createEdge();
        this.bottom = this.createEdge();
        this.left = this.createEdge();
    }

    /**
     * Highlights the given element.
     *  
     * @param element
     */
    this.select = function(element) {
        if(!element || this.isInvisible(element)) {
            element = null;
        }
        this.selectedElement = element;
        this.updateLayout();
    }

    /**
     * @return HTMLElement Currently selected page element.
     */
    this.getSelectedElement = function()
    {
        return this.selectedElement;
    }

    /**
     * @private
     */
    this.createEdge = function() {
        var edge = new core.ui.Window();
        edge.setStyle('z-index', 2147483647);
        edge.setStyle('background-color', 'yellow');
        return edge;
    }

    /**
     * @private
     *
     * Updates control position and layout.
     */
    this.updateLayout = function() {
        var visible = !!this.selectedElement;
        if (visible) {
            // TODO: re-create edges within the element's document

            var offset = this.getElementOffset(true);
            var w = this.selectedElement.offsetWidth;
            var h = this.selectedElement.offsetHeight;

            this.top.move(offset.x, offset.y - Selection.EDGE_SIZE);
            this.top.resize(w, Selection.EDGE_SIZE);

            this.right.move(offset.x + w, offset.y - Selection.EDGE_SIZE);
            this.right.resize(Selection.EDGE_SIZE, h + Selection.EDGE_SIZE * 2);

            this.bottom.move(offset.x, offset.y + h);
            this.bottom.resize(w, Selection.EDGE_SIZE);

            this.left.move(offset.x - Selection.EDGE_SIZE, offset.y - Selection.EDGE_SIZE);
            this.left.resize(Selection.EDGE_SIZE, h + Selection.EDGE_SIZE * 2);
            
        } else {
            // TODO: remove edges from document
        }
        this.top.setVisible(visible);
        this.right.setVisible(visible);
        this.bottom.setVisible(visible);
        this.left.setVisible(visible);
    }

    /**
     * @private
     *
     * Checks whether the given element is invisible.
     *
     * @param element
     */
    this.isInvisible = function(element) {
        return ((0 == element.offsetWidth) && (0 == element.offsetHeight)) || !element.nodeName ||
               (element.nodeName.toLowerCase() in Selection.INVISIBLE_TAGS) ||
               (element.namespaceURI == Selection.SVG_NAMESPACE);
    }

    /**
     * @private
     * @return Map with "x" and "y" offsets.
     */
    this.getElementOffset = function()
    {
        var elt = this.selectedElement;
        function addOffset(elt, coords, view)
        {
            var p = elt.offsetParent;
            coords.x += elt.offsetLeft - (p ? p.scrollLeft : 0);
            coords.y += elt.offsetTop - (p ? p.scrollTop : 0);

            if (p)
            {
                if (p.nodeType == 1)
                {
                    var parentStyle = view.getComputedStyle(p, "");
                    if (parentStyle.position != "static")
                    {
                        coords.x += parseInt(parentStyle.borderLeftWidth);
                        coords.y += parseInt(parentStyle.borderTopWidth);

                        if (p.localName == "TABLE")
                        {
                            coords.x += parseInt(parentStyle.paddingLeft);
                            coords.y += parseInt(parentStyle.paddingTop);
                        }
                        else if (p.localName == "BODY")
                        {
                            var style = view.getComputedStyle(elt, "");
                            coords.x += parseInt(style.marginLeft);
                            coords.y += parseInt(style.marginTop);
                        }
                    }
                    else if (p.localName == "BODY")
                    {
                        coords.x += parseInt(parentStyle.borderLeftWidth);
                        coords.y += parseInt(parentStyle.borderTopWidth);
                    }

                    var parent = elt.parentNode;
                    while (p != parent)
                    {
                        coords.x -= parent.scrollLeft;
                        coords.y -= parent.scrollTop;
                        parent = parent.parentNode;
                    }
                    addOffset(p, coords, view);
                }
            }
            else
            {
                if (elt.localName == "BODY")
                {
                    var style = view.getComputedStyle(elt, "");
                    coords.x += parseInt(style.borderLeftWidth);
                    coords.y += parseInt(style.borderTopWidth);

                    var htmlStyle = view.getComputedStyle(elt.parentNode, "");
                    coords.x -= parseInt(htmlStyle.paddingLeft);
                    coords.y -= parseInt(htmlStyle.paddingTop);
                }

                if (elt.scrollLeft)
                    coords.x += elt.scrollLeft;
                if (elt.scrollTop)
                    coords.y += elt.scrollTop;
            }
        }

        var coords = {x: 0, y: 0};
        addOffset(elt, coords, elt.ownerDocument.defaultView);
        return coords;
    }
}

/**
 * @private
 * Collection of invisible tag names.
 */
xcms.plugins.editor.Selection.INVISIBLE_TAGS = {
    'html' : true,
    'head' : true,
    'title' : true,
    'meta' : true,
    'link' : true,
    'style' : true,
    'script' : true,
    'noscript' : true,
    'br' : true
}

/**
 * @private
 * Width of each selection edge.
 */
xcms.plugins.editor.Selection.EDGE_SIZE = 4;

/**
 * @private
 */
xcms.plugins.editor.Selection.SVG_NAMESPACE = 'http://www.w3.org/2000/svg';